/**
 * 
 */
package com.gragra.sampling.nonproj;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
import com.gragra.benchmark.CountingAssigner;
import com.gragra.sampling.PopulationSamplingStructure;
import com.gragra.sampling.nonproj.structures.nonprojective.NonProjDepdTree;
/**
 * @author Christoph Teichmann
 * 09.09.2013
 */
public class FixedParsesAssigner implements ProposalDependencyAssigner, CountingAssigner
{
	/**
	 * 
	 */
	private final int[][] arr;
	/**
	 * 
	 */
	private final int popSize;
	/**
	 * @param popSize
	 * @param fact
	 * @param depth
	 * @param map
	 */
	public FixedParsesAssigner(int popSize, double fact, int depth, Collection<String> gold)
	{
		super();
		this.popSize = popSize;
		this.fact = fact;
		this.depth = depth;
		arr = this.makeArr(gold);
	}
	/**
	 * 
	 * @param gold
	 * @return
	 */
	private int[][] makeArr(Collection<String> gold)
	{
		int[][] ret = new int[gold.size()][];
		int pos = 0;
		for(String s : gold)
		{ret[pos++] = transfer(s);}
		return ret;
	}
	/**
	 * 
	 * @param s
	 * @return
	 */
	private int[] transfer(String s)
	{
		String[] parts = s.split("\\s+");
		int[] ret = new int[parts.length];
		for(int i = 0; i < parts.length; i++)
		{
			String q = parts[i];
			ret[i] = Integer.parseInt(q);
		}
		return ret;
	}
	/* (non-Javadoc)
	 * @see com.gragra.sampling.PopulationProbabilityAssigner#getPopulationSize()
	 */
	@Override
	public int getPopulationSize()
	{return this.popSize;}
	@Override
	public double makeLogProb(PopulationSamplingStructure pps, int number)
	{
		NonProjDepdTree nonProjStruct = (NonProjDepdTree) pps;
		this.functEval.addAndGet(nonProjStruct.getLength());
		double best = Double.NEGATIVE_INFINITY;
		for(int[] a : arr)
		{
			double val = 0.0;
			for(int i=0;i<nonProjStruct.getLength();++i)
			{
				int oh = nonProjStruct.getParentPosition(i, number);
				int gh = a[i];
				boolean matched = true;
				for(int d=0;d<depth;++d)
				{
					matched &= oh == gh;
					if(!matched || oh == nonProjStruct.getRootPosition())
					{break;}
					gh = a[gh];
					oh = nonProjStruct.getParentPosition(oh, number);
				}
				val += matched ? this.fact : 0.0;
			}
			best = Math.max(best, val);
		}
		return best;
	}
	/**
	 * 
	 */
	private final AtomicInteger functEval = new AtomicInteger();
	/**
	 * 
	 */
	private final double fact;
	/**
	 * 
	 */
	private final int depth;
	@Override
	public double getNumberOfEvaluations()
	{return this.functEval.get();}
	@Override
	public double getNumberOfAuxEvals()
	{return this.auxs.get();}
	@Override
	public void add(PopulationSamplingStructure pss, int thread)
	{}
	@Override
	public void remove(PopulationSamplingStructure pss, int thread)
	{}
	@Override
	public double getNonLocalLogLike(int num)
	{return 0.0;}
	@Override
	public double getLocalLogLike(PopulationSamplingStructure pss, int thread)
	{return this.makeLogProb(pss, thread);}
	@Override
	public double makeProposalLogProb(int pos, int head,
			NonProjDepdTree tree, int thread)
	{
		this.auxs.addAndGet(tree.getLength());
		NonProjDepdTree nonProjStruct = (NonProjDepdTree) tree;
		double best = Double.NEGATIVE_INFINITY;
		for(int[] a : arr)
		{
			double val = 0.0;
			for(int i=0;i<nonProjStruct.getLength();++i)
			{
				int oh = nonProjStruct.getParentPosition(i, thread);
				int gh = a[i];
				boolean matched = true;
				for(int d=0;d<depth;++d)
				{
					if(oh == -1)
					{break;}
					matched &= oh == gh;
					if(!matched || oh == nonProjStruct.getRootPosition())
					{break;}
					gh = a[gh];
					oh = nonProjStruct.getParentPosition(oh, thread);
				}
				val += matched ? this.fact : 0.0;
			}
			best = Math.max(best, val);
		}
		return best;
	}
	/**
	 * 
	 */
	private AtomicInteger auxs = new AtomicInteger();
	@Override
	public double makeChartProposalProb(
			NonProjDepdTree tree,
			int headCandidate, int child, int thread)
	{
		auxs.incrementAndGet();
		for(int[] a : this.arr)
		{
			if(a[child]==headCandidate)
			{return this.fact;}
		}
		return 0.0;
	}
	@Override
	public void reduceStructuralAnnealing(int p)
	{}
}